﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Netra
{
    class TradeMgmt
    {
        public static TradeMgmt Deals=new TradeMgmt();
        enum EStatus
        {
            Registered,
            Executed,
            Incomplete
        }
        private class Trade
        {
            public Merch Ware;
            protected int quantity;
            public virtual int Quantity
            {
                get { return quantity; }
            }
            public EStatus Status;

            public Trade(Merch ware, int pquantity, EStatus status)
            {
                Ware = ware;
                quantity = pquantity;
                Status = status;
            }
        }
        private class Purchase:Trade
        {
            public Planet Seller;
            public Fleet Purchaser;

            public override int Quantity
            {
                get
                {
                    return Math.Min(quantity,Purchaser.StorageAvail);
                }
            }

            public Purchase(Planet seller, Fleet purchaser, Merch ware, int quantity, EStatus status):base(ware,quantity,status)
            {
                if (!seller.InDock(purchaser))
                    throw new System.InvalidOperationException("Cannot register purchase between planet and fleet not in dock");
                Seller = seller;
                Purchaser = purchaser;
            }
        }
        private class Sale:Trade
        {
            public Fleet Seller;
            public Planet Purchaser;
            
            public Sale(Fleet seller, Planet purchaser, Merch ware, int quantity, EStatus status):base(ware,quantity,status)
            {
                if (!purchaser.InDock(seller))
                    throw new System.InvalidOperationException("Cannot register sale between planet and fleet not in dock");
                Seller = seller;
                Purchaser = purchaser;
            }
        }

        private List<Purchase> purchases;
        private List<Sale> sales;

        public TradeMgmt()
        {
            purchases = new List<Purchase>();
            sales = new List<Sale>();
        }

        public void RegisterPurchase(Planet seller, Fleet purchaser, Merch ware, int quantity)
        {
            purchases.Add(new Purchase(seller,purchaser,ware,quantity,EStatus.Registered));
        }

        public void RegisterSale(Fleet seller, Planet purchaser, Merch ware, int quantity)
        {
            sales.Add(new Sale(seller, purchaser, ware, quantity, EStatus.Registered));
        }

        private void CommitPurchases()
        {
            foreach (Purchase purch in purchases)
            {
                if(purch.Status==EStatus.Executed)
                    continue;

                Merch ware=purch.Ware;
                Store store=purch.Seller.store;
                //Console.Write("purch: planet:{0} merchandise:{1}\n",purch.Seller.Name,ware.Name);
                IEnumerable<Purchase> MerchPlanetTrade = purchases.Select(t => t).Where(t => t.Seller == purch.Seller && t.Ware == purch.Ware).OrderBy(t=>t.Purchaser.Reputation());
                //int sum = MerchPlanetTrade.Select(t => t.Quantity).Sum();
                //int tosell=store.MaxSellQuantity(ware);

                //Console.Write("Suma: {0}\n", sum);
                foreach (Purchase x in MerchPlanetTrade)
                {
                    int amount = Math.Min(x.Quantity, store.MaxBuyQuantity(ware));
                    //Console.Write(" purchase: quantity:{0} amount:{1} avail:{2}\n", x.Quantity,amount,store.MaxSellQuantity(ware));
                    //Console.Write(" purchase: fleet:{0} amount:{1}\n", purch.Purchaser.Name, amount);
                    if (amount > 0)
                    {
                        x.Seller.store.Buy(purch.Ware, amount);
                        x.Purchaser.AddMerch(purch.Ware, amount);
                    }
                    x.Status = EStatus.Executed;
                }




            }
        }

        private void CommitSales()
        {
            foreach (Sale sale in sales)
            {
                if (sale.Status == EStatus.Executed)
                    continue;

                Merch ware = sale.Ware;
                //Console.Write("sale: planet:{0} merchandise:{1}\n", sale.Seller.Name, ware);
                IEnumerable<Sale> PlanetMerchSales = sales.Select(t => t).Where(t => t.Purchaser == sale.Purchaser && t.Ware == sale.Ware).OrderBy(t=>t.Seller.Reputation());
                foreach (Sale s in PlanetMerchSales)
                {
                    int amount = Math.Min(s.Quantity, s.Purchaser.store.MaxSellQuantity(ware));
                    if (amount > 0)
                    {
                        s.Seller.TakeMerch(ware, amount);
                        s.Purchaser.store.Sell(ware, amount);
                    }
                    s.Status = EStatus.Executed;
                }

            }
        }

        public void Commit()
        {
            CommitPurchases();
            CommitSales();
        }
    }
}
